/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ASemantico;

import GeneradorCodigo.generador;
import TablaSimbolos.TabladeSimbolos;
import TablaSimbolos.entradaClase;
import TablaSimbolos.entradaMetodo;
import TablaSimbolos.parametro;
import java.util.ArrayList;

/**
 *
 * @author alfredo
 */
public class controlesSemanticos {

    TabladeSimbolos TS;
    boolean izquierdo = true;
    int lineaActual;
    boolean inWhile = false;
    boolean inIf = false;
    boolean inFor = false;
    
    
    
    /*
     * Inicializa los controles semanticos.
     * tareas:
     */
    public TabladeSimbolos getTabladeSimbolos() throws Exception {
        if (TS != null) {
            return TS;
        } else {
            throw new Exception("la tabla de simbolos no esta inicializada");
        }
    }

    public boolean isInFor() {
        return inFor;
    }

    public void setInFor(boolean inFor) {
        this.inFor = inFor;
    }

    public boolean isInIf() {
        return inIf;
    }

    public void setInIf(boolean inIf) {
        this.inIf = inIf;
    }

    public boolean isInWhile() {
        return inWhile;
    }

    public void setInWhile(boolean inWhile) {
        this.inWhile = inWhile;
    }
    
    
    public controlesSemanticos() {
        TS = new TabladeSimbolos();
    }

    public int getLineaActual() {
        return lineaActual;
    }

    public void setLineaActual(int lineaActual) {
        this.lineaActual = lineaActual;
        TS.setLineaActual(lineaActual);
    }

    public boolean isIzquierdo() {
        return izquierdo;
    }

    public void setIzquierdo(boolean izquierdo) {
        this.izquierdo = izquierdo;
    }

    public void comprobadorSemantico() throws Exception {
        TS.mostrarClases();
    }

    public String getBooleanType() {
        return "boolean";
    }

    public String getCharType() {
        return "char";
    }

    public String getIntType() {
        return "int";
    }

    public String getStringType() {
        return "String";
    }

    public String getVoidType() {
        return "void";
    }

    public String getNullType() {
        return "null";
    }

    public String getObjectType() {
        return "Object";
    }

    public String getSystemType() {
        return "System";
    }

    public String claseActual() {
        return TS.claseActual();
    }
    //ok

    public void setClaseActual(String nombreClase) {
        TS.setearClaseActual(nombreClase);
    }

    //ok
    public void inicializacionControlesSemanticos() throws Exception {
        TS.inicializarTS();
    }
    //ok

    public void comprobarEspecificacionesPendientes() throws Exception {
        TS.verificarDefinidos();
        TS.verificarMetodosDefinidos();
    }

    public void quitarMetodoEspecificacionPendiente(String nombreMetodo) throws Exception {
        TS.quitarMetodoEspecificacionPendiente(nombreMetodo);
    }
    //ok

    public void comprobarDeclaracionesPendientes() throws Exception {
        TS.verificarDeclarados();
    }
    //ok

    public atributo crearSintetizadoHierarchy(String nombreClase) {
        atributo a = new atributo();
        a.setNombreClase(nombreClase);
        return a;
    }
    //ok

    public void agregarClaseDef(String entryClass) throws Exception {
        TS.agregarClaseDef(entryClass);
    }
    //TODO review is this method is necesary put in others places

    public void agregarClasePendiendteTS(String nombreClase) {
        TS.agregarClaseTS(nombreClase);
    }
    //ok

    public void agregarHerencia(String claseActual, String nombreClasePadre) throws Exception {
        TS.agregarHerencia(claseActual, nombreClasePadre);
        TS.agregarMetodosPadre();
    }
    //ok

    private boolean claseActualTieneConstructor() {
        return TS.claseActualTieneConstructor();
    }

    /*Comprueba si tiene constructor, sino tiene crea el constructor por defecto
     *      
     */
    //TODO crearConstructorPorDefecto
    public void comprobarTieneConstructor() throws Exception {
        if (!claseActualTieneConstructor()) {
            TS.crearConstructorPorDefecto();
        }
    }
    //ok

    public atributo crearSintetizadoConsMethodDef(String idOTipo) {
        atributo a = new atributo();
        a.setIdentificadorOTipo(idOTipo);
        return a;
    }
    //ok

    public void agregarMetodo(String tipoRetorno, String Identificador) throws Exception {
        TS.agregarMetodo(claseActual(), tipoRetorno, Identificador, TS.obtenerListaTemporalParametros());
    }
    //ok

    public void controlarNombreConstructor(String nombreConstructor) throws Exception {
        if (!claseActual().equals(nombreConstructor)) {
            throw new Exception("\n<---------- ERROR en el analisis ---------->\nTipo de error: semantico\nDetalle: El nombre del constructor: " + nombreConstructor + " no corresponde con el nombre de la clase: "
                    + claseActual() + "\nEncontrado en linea: " + getLineaActual() + "\n<------------------------------------------>");
        }
    }
    //ok

    public void agregarConstructor() throws Exception {
        //TS.agregarMetodo(claseActual(),claseActual(),claseActual(), TS.obtenerListaTemporalParametros());
        TS.agregarConstructor();
    }
    //ok

    public void agregarParametrosListaTemporal(String identificador, String tipo) {
        parametro p = new parametro(identificador, tipo);
        //p.setTipo(tipo);
        //p.setIdentificador(identificador);
        TS.agregarParametrosTemporales(p);
    }
    //ok

    public void limpiarListaTemporalParametros() {
        TS.limpiarListaParametrosTemporales();
    }
    //ok

    public atributo crearSintetizadoFormalArg(String identificador, String tipo) {
        atributo a = new atributo();
        a.setType(tipo);
        a.setLexema(identificador);
        return a;
    }
    //ok

    public atributo crearSintetizadoType(String tipo) {
        atributo a = new atributo();
        a.setType(tipo);
        return a;
    }
    //ok

    public atributo crearHeredadoMethodDef(String type) {
        atributo a = new atributo();
        a.setType(type);
        return a;
    }
    //ok

    public void controlarDefinicionDeClase(String nombreClasePadre) throws Exception {
        // controlar que la clase actual este definida como hija de
        //la clase padre
        TS.controlarDefinicionDeClase(nombreClasePadre);
        TS.agregarVariablesPadres();
    }
    //ok

    public void quitarClaseDeListaPendienteEspecificacion() {
        TS.quitarClaseDeListaPendienteEspecificacion();
    }
    //ok

    public atributo crearHeredadofieldConstMethod(String identificadorOtipo) {
        atributo a = new atributo();
        a.setIdentificadorOTipo(identificadorOtipo);
        return a;
    }
    //ok

    public atributo crearHeredadoMethod(String type) {
        atributo a = new atributo();
        a.setType(type);
        return a;
    }
    //ok

    public void controlarConstructor() throws Exception {
        TS.controlarConstructor();
    }
    //ok

    //setea el metodo actual en la tabla de simbolos
    //y setear el offset , el label de donde esta el codigo del metodo;
    public void setearMetodo(String nombreMetodo) throws Exception {
        TS.setearMetodo(nombreMetodo);
    }

    public String metodoActual() {
        return TS.getMetodoActual();
    }
    //ok

    public void quitarConstructorEspecificacionPendiente() throws Exception {
        TS.quitarConstructorEspecificacionPendiente();
    }
    //ok

    public atributo crearHeredadoFieldMethod(String tipo, String nombreMetodo) {
        atributo a = new atributo();
        a.setType(tipo);
        a.setNombreMetodo(nombreMetodo);
        return a;
    }
    //ok

    public atributo crearHeredadoListaField(String tipo) {
        atributo a = new atributo();
        a.setType(tipo);
        return a;
    }
    //ok concuerda con declaracion

    public void controlarMetodo(String nombreMetodo, String tipo) throws Exception {
        TS.concuerdaConDeclaracion(claseActual(), nombreMetodo, tipo, TS.obtenerListaTemporalParametros());
    }
    //ok

    public atributo crearHeredadoRestoField(String tipo) {
        atributo a = new atributo();
        a.setType(tipo);
        return a;
    }
    //ok

    public void agregarAtributoAClase(String tipo, String identifier) throws Exception {
        TS.agregarAtributoAClase(tipo, identifier);
    }
    //ok
    //TODO

    public void controlarRetornos(String claseActual, String metodoActual, atributo atrBloque) throws Exception {
        entradaClase eC = TS.darClase(claseActual);
        entradaMetodo eM = eC.darMetodo(metodoActual);
        entradaClase claseRetorno = eM.darRetornoMetodo();
        String tipoRetorno = claseRetorno.darNombre();
        if (!claseActual.equals(metodoActual)) {//es un constructor
            if (!TS.sonTiposAdmisibles(atrBloque.getType(), tipoRetorno)) {
                String msg = "El tipo de retorno del metodo no es el esperado. Metodo: " + metodoActual;
                throw new Exception(msg);
            }
        }
        
    }

    public void controlarSentenciaReturnEnConstructor(boolean esConstructor) throws Exception {
        if (esConstructor) {
            String msg = "En los constructores de clase no esta permitido la sentencia 'Return'. Linea: " + TS.getLineaActual();
            throw new Exception(msg);
        }
    }

    //ok
    public atributo crearHeredadoClassBodyConstMethodResto(String nombreMetodo) {
        atributo a = new atributo();
        a.setNombreMetodo(nombreMetodo);
        return a;
    }
    //TODO

    public void statementReturnControlarTipoRetorno(String tipo) throws Exception {
        TS.controlarTipoRetorno(tipo);
    }
    
    /*public void ultimaSentenciaReturn(String nombreClase, String nombreMetodo, boolean ultimasentenciaConstructor) throws Exception{
        if(!ultimasentenciaConstructor){
            String msg = "Se ha restringido la implementacion del lenguaje. La ultima sentencia de un metodo debe ser un return" + TS.getLineaActual();
            throw new Exception(msg);
        }
    }*/

    private static boolean esNumeroEntero(String cadena) {
        try {
            Integer.parseInt(cadena);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }

    public void controlarNumero(String nro) throws Exception {

        if (!esNumeroEntero(nro)) {
            throw new Exception("el numero" + nro + "No es un numero representable en DECAF" + ". Linea: " + getLineaActual());
        }
    }

    /**
     * Verifica que la clase Main este presente en la tabla de simbolos.
     * @return Devuelve true en caso de que la clase Main este declarada.
     * Luego se verificara si la misma esta definida.
     * @throws Exception Arroja un error en el caso de que la clase Main
     * no este declarada.
     */
    public void estaMain() throws Exception {
        TS.estaMain();
    }

    /*public void setAsignableExpression(boolean asignable){
    if(this.izquierdo) {
    TS.setIsAssignable(asignable);
    }
    }*/
    //ok
    public atributo crearSintetizadoStatementResto(String tipo) {
        atributo a = new atributo();
        a.setType(tipo);
        return a;
    }
    //ok

    public void controlarTipoExpression(String tEsperado, String tActual) throws Exception {
        String msg;
        String sentencia = "";
        if(isInFor()) sentencia = ".Sentencia: FOR";
        if(isInIf()) sentencia =".Sentencia: IF";
        if(isInWhile()) sentencia =".Sentencia: While";
        if (tEsperado.equals(this.getBooleanType())) {
            if (!tEsperado.equals(tActual)) {
                msg = "Se esperaba un tipo booleano y se encontro: " + tActual + sentencia ;
                throw new Exception(msg);
            }
        }
        if (tEsperado.equals(this.getCharType())) {
            if (!tEsperado.equals(tActual)) {
                msg = "Se esperaba un tipo char y se encontro: " + tActual + sentencia ;
                throw new Exception(msg);
            }
        }
        if (tEsperado.equals(this.getIntType())) {
            if (!tEsperado.equals(tActual)) {
                msg = "Se esperaba un tipo int y se encontro: " + tActual + sentencia ;
                throw new Exception(msg);
            }
        }
        if (tEsperado.equals(this.getStringType())) {
            if (!tEsperado.equals(tActual)) {
                msg = "Se esperaba un tipo String y se encontro: " + tActual + sentencia ;
                throw new Exception(msg);
            }
        }
        if (tEsperado.equals(this.getVoidType())) {
            if (!tEsperado.equals(tActual)) {
                msg = "Se esperaba que no tuviera tipo: " + tActual + sentencia ;
                throw new Exception(msg);
            }
        }
    }

    public atributo expression(atributo condOrExpres, atributo expFact,ArrayList<String> arrayVar,generador gc) throws Exception {
        String msg;
        atributo a = new atributo();
        if (!expFact.isIsEmpty()) {
            //Es una asignacion
            //if(!TS.isAssignable()){//si el lado izquierdo es asignable -->es una variable
            if (!condOrExpres.isAsignable()) {
                msg = "Asignacion invalida" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                if (TS.sonTiposAdmisibles(condOrExpres.getType(), expFact.getType())) {
                    //TODO
                    //Generador de codigo Asignar
                    int offset = arrayVar.size() ;
                    String identificadorVar = arrayVar.get(offset - 1) ;
                    gc.almacenarValorEnVariable(identificadorVar);
                    a.setType(condOrExpres.getType());
                } else {
                    msg = "Error de tipo, la asignacion no es admisibles. Linea: " + getLineaActual();
                    throw new Exception(msg);
                }
            }
        } else {
            a.setType(condOrExpres.getType());
        }
        return a;
    }
    //ok

    public atributo crearSintetizadoExpressionFact(String tipo, boolean isEmpty) {
        atributo a = new atributo();
        a.setType(tipo);
        a.setIsEmpty(isEmpty);
        return a;
    }
    //ok

    public atributo crearSintetizadoExpressionFact(boolean isEmpty) {
        atributo a = new atributo();
        a.setIsEmpty(isEmpty);
        return a;
    }
    //ok

    public atributo conditionalOrExpression(atributo condAndExp, atributo condOrExprRec) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!condOrExprRec.isIsEmpty()) {
            if (!condOrExprRec.getType().equals(getBooleanType())
                    || !condAndExp.getType().equals(getBooleanType())) {
                msg = "operador || aplicado a operadores de tipo erroneos" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(condAndExp.getType());
            }
        } else {
            a.setAsignable(condAndExp.isAsignable());
            a.setType(condAndExp.getType());
        }
        return a;
    }
    //ok

    public atributo conditionalOrExpressionRec(atributo condAndExp, atributo condOrExpRec1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!condOrExpRec1.isIsEmpty()) {
            if (!condAndExp.getType().equals(getBooleanType())
                    || condOrExpRec1.getType().equals(getBooleanType())) {
                msg = "el operador || no se puede aplicar a los operadores de tipo: " + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(condAndExp.getType());
                a.setIsEmpty(false);
            }
        } else {
            a.setType(condAndExp.getType());
        }
        return a;
    }
    //ok

    public atributo conditionalOrExpressionRec() throws Exception {
        atributo a = new atributo();
        a.setIsEmpty(true);
        return a;
    }
    //ok

    public atributo conditionalAndExpression(atributo eqExpression, atributo condAndExpRec) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!condAndExpRec.isIsEmpty()) {
            if (!condAndExpRec.getType().equals(getBooleanType())
                    || !eqExpression.getType().equals(getBooleanType())) {
                msg = "operador && aplicado a operadores de tipo erroneos " + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(eqExpression.getType());
            }
        } else {
            a.setAsignable(eqExpression.isAsignable());
            a.setType(eqExpression.getType());
        }
        return a;
    }
    //ok

    public atributo conditionalAndExpressionRec(atributo eqExpression, atributo condAndExpRec1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!eqExpression.getType().equals(getBooleanType()) || (!condAndExpRec1.isIsEmpty()
                && !condAndExpRec1.getType().equals(getBooleanType()))) {
            msg = "operador && aplicado a operadores de tipo erroneos" + ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            a.setType(getBooleanType());
            a.setIsEmpty(false);
        }
        return a;
    }
    //ok

    public atributo conditionalAndExpressionRec() throws Exception {
        atributo a = new atributo();
        a.setIsEmpty(true);
        return a;
    }
    //ok

    public atributo equalityExpression(atributo relationalExp, atributo eqExpressionRec) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!eqExpressionRec.isIsEmpty()) {
            if (!TS.sonTiposAdmisibles(relationalExp.getType(), eqExpressionRec.getType())) {
                msg = "La operacion no se puede aplicar sobre operandos de tipo " + relationalExp.getType() + " y de tipo " + eqExpressionRec.getType()+ ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getBooleanType());
            }
        } else {
            a.setAsignable(relationalExp.isAsignable());
            a.setType(relationalExp.getType());
        }
        return a;
    }
    //ok

    public atributo equalityExpressionRec(atributo relationalExp, atributo eqExpressionRec1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!eqExpressionRec1.isIsEmpty()) {
            if (TS.sonTiposAdmisibles(relationalExp.getType(), eqExpressionRec1.getType())) {
                a.setType(getBooleanType());
            } else {
                msg = "La operacion no se puede aplicar a operandos de tipo " + relationalExp.getType() + " y de tipo " + eqExpressionRec1.getType()+ ". Linea: " + getLineaActual();
                throw new Exception(msg);
            }
        } else {
            a.setType(relationalExp.getType());
        }
        return a;
    }
    //ok

    public atributo equalityExpressionRec() throws Exception {
        atributo a = new atributo();
        a.setIsEmpty(true);
        a.setAsignable(false);
        return a;
    }
    //ok

    public atributo relationalExpression(atributo addExpression, atributo relationalExpFact) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!relationalExpFact.isEmpty) {
            if (!addExpression.getType().equals(getIntType()) || !relationalExpFact.getType().equals(getIntType())) {
                msg = "Expresion Realcional aplicada operandos que no son enteros" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getBooleanType());
            }
        } else {
            a.setAsignable(addExpression.isAsignable());
            a.setType(addExpression.getType());
        }

        return a;
    }
    //ok

    public atributo additiveExpression(atributo addExp) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!addExp.getType().equals(getIntType())) {
            msg = "Expresion Realcional aplicada operandos que no son enteros"+ ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            a.setType(getIntType());
        }
        return a;
    }
    //ok

    public atributo additiveExpression(atributo multExp, atributo addExp) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!addExp.isIsEmpty()) {
            if (!multExp.getType().equals(getIntType()) || !addExp.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros"+ ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getIntType());
            }
        } else {
            a.setAsignable(multExp.isAsignable());
            a.setType(multExp.getType());
        }
        return a;
    }
    //ok

    public atributo additiveExpressionRec(atributo multExp, atributo addExpRec1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!addExpRec1.isIsEmpty()) {
            if (!multExp.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getIntType());
            }
        } else {
            if (!multExp.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setAsignable(multExp.isAsignable());
                a.setType(multExp.getType());
            }
        }
        return a;
    }
    //ok

    public atributo additiveExpressionRec() {
        atributo a = new atributo();
        String msg;
        a.setIsEmpty(true);
        a.setAsignable(false);
        return a;
    }
    //ok

    public atributo multiplicativeExpression(atributo unaryExp, atributo multExp) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!multExp.isIsEmpty()) {
            if (!unaryExp.getType().equals(getIntType()) || !multExp.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros" + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getIntType());
            }
        } else {
            a.setAsignable(unaryExp.isAsignable());
            a.setType(unaryExp.getType());
        }
        return a;
    }
    //ok

    public atributo multiplicativeExpressionRec(atributo unaryExp, atributo multExpRec1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!unaryExp.getType().equals(getIntType())) {
            msg = "Expresion aplicada a operandos que no son enteros"+ ". Linea: " + getLineaActual();
            throw new Exception(msg);
        }
        if (!multExpRec1.isIsEmpty()) {
            if (!multExpRec1.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros"+ ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setType(getIntType());
            }
        } else {
            if (!unaryExp.getType().equals(getIntType())) {
                msg = "Expresion aplicada a operandos que no son enteros"+ ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setAsignable(unaryExp.isAsignable());
                a.setType(unaryExp.getType());
            }
        }

        return a;
    }
    //ok

    public atributo multiplicativeExpressionRec() {
        atributo a = new atributo();
        a.setIsEmpty(true);
        a.setAsignable(false);
        return a;
    }
    //ok

    public atributo unaryExpression(atributo unaryExp1) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!unaryExp1.getType().equals(getIntType())) {
            msg = "Expresion aplicada a operandos que no son enteros"+ ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            a.setType(getIntType());
        }
        a.setAsignable(unaryExp1.isAsignable());
        return a;
    }
    //ok

    public atributo unaryExpressionPrimary(atributo primary) {
        atributo a = new atributo();
        a.setType(primary.getType());
        a.setAsignable(primary.isAsignable());
        return a;
    }
    //ok

    public atributo primaryExpressionToPrimaryRec(atributo expression) {
        atributo a = new atributo();
        a.setType(expression.getType());
        a.setAsignable(false);
        //this.setAsignableExpression(true);
        return a;
    }
    //ok

    public atributo primaryNewIdToActualArgs(String identificador) throws Exception {
        atributo a = new atributo();
        String msg;
        a.setAsignable(false);
        if (!TS.perteneceTS(identificador)) {
            msg = "No se puede encontrar el contructor para la clase " + identificador + ". Linea: " + getLineaActual();
            throw new Exception(msg);
        }
        a.setIsNew(true);
        a.setNombreMetodo(identificador);
        return a;
    }
    //ok

    public atributo primaryActualArgsToPrimaryRec(atributo actualArgs) {
        atributo a = new atributo();
        a.setType(actualArgs.getType());
        a.setAsignable(actualArgs.isAsignable());
        return a;
    }
    //ok

    public atributo primarySuperIdToActualArgs(String identifier) {

        atributo a = new atributo();
        a.setNombreMetodo(identifier);
        a.setIsSuper(true);
        a.setAsignable(false);
        return a;
    }
    //ok

    public atributo primaryLiteralToPrimaryRec(atributo literal) {
        atributo a = new atributo();
        a.setIsLiteral(true);
        a.setType(literal.getType());
        a.setAsignable(false);
        return a;

    }
    //ok

    public void primaryRecIsLiteral(atributo primaryRec) throws Exception {
        String msg = null;
        if (primaryRec.isIsLiteral()) {
            msg = "no es posible realizar una llamada calificada sobre un literal"+ ". Linea: " + getLineaActual();
            throw new Exception(msg);
        }
    }
    //ok

    public atributo primaryRecIdToActualArgs(atributo primaryRec, String identificador) throws Exception {
        atributo a = new atributo();
        String tipo;
        String msg;
        tipo = TS.tipoRetornoMetodo(primaryRec.getType(), identificador);
        if (tipo == null) {
            msg = "\n<---------- ERROR en el analisis ---------->\nTipo de error: semantico\n"
                    + "Detalle: El metodo " + identificador + " no es un metodo declarado en la clase: " + primaryRec.getType()
                    + "\nEncontrado en linea: " + getLineaActual() + "\n<------------------------------------------>";
            throw new Exception(msg);
        } else {
            a.setType(primaryRec.getType());
            a.setNombreMetodo(identificador);
        }
        return a;
    }
    //ok

    public atributo primaryRecActualArgsToPrimaryRec(atributo actualArgs) {
        atributo a = new atributo();
        a.setType(actualArgs.getType());
        return a;
    }
    //ok

    public atributo primaryRecEmpty(atributo primaryRec) {
        atributo a = new atributo();
        a.setType(primaryRec.getType());
        a.setIsEmpty(true);
        a.setAsignable(primaryRec.isAsignable());
        return a;
    }
    //ok

    public atributo restoIdBeforeActualArgs(atributo restoId) throws Exception {
        atributo a = new atributo();
        entradaClase eC = TS.darClase(claseActual());
        entradaMetodo eM = eC.darMetodo(restoId.getLexema());
        //entradaVariable eV = eC.darVariable(restoId.getLexema());
        //String tipo = eV.darTipo().darNombre();
        String msg;
//        tipo = TS.tipoRetornoMetodo(claseActual(), restoId.getLexema());
          if (eM == null) {
            msg = "el metodo " + restoId.getLexema() + "no es un metodo declarado en la clase"
                    + claseActual() + ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            a.setType(TS.claseActual());
            a.setNombreMetodo(restoId.getLexema());
        }
        return a;
    }
    //ok

    public atributo primaryRecIsAvar(atributo restoId) throws Exception {
        //agregue este comentario
        atributo a = new atributo();
        String msg;
        String tipo;
        if (restoId.getLexema().equals("System")) {
            tipo = getSystemType();
            a.setAsignable(false);
            a.setType(tipo);
            a.setLexema(restoId.getLexema());
        } else {
            tipo = TS.buscarTipoDeVar(restoId.getLexema());
            if (tipo == null) {
                msg = "La variable " + restoId.getLexema() + "no es una variable alcanzable " + ". Linea: " + getLineaActual();
                throw new Exception(msg);
            } else {
                a.setAsignable(true);
                a.setType(tipo);
                a.setLexema(restoId.getLexema());
                
            }
        }
        return a;
    }
    //TODO

    public atributo restoThisIDTorestoThisFact(String identificador) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!TS.esVariableInstancia(identificador) && !TS.esMetodo(identificador)) {
            msg = "El identificador " + identificador + " no corresponde ni a una variable de instancia ni a un metodo de clase" + ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            a.setLexema(identificador);
            a.setAsignable(true);
        }
        return a;
    }
    //ok

    public atributo restoThisEmpty() {
        atributo a = new atributo();
        a.setIsEmpty(true);
        a.setAsignable(true);
        return a;
    }
    //ok

    public atributo restoThisFactActualArgsToPrimary(atributo restoThisFact) throws Exception {
        atributo a = new atributo();
        String msg;
        String tipo;
        if (TS.esMetodo(restoThisFact.getLexema())) {
            a.setType(TS.tipoRetornoMetodo(claseActual(), restoThisFact.getLexema()));
            a.setNombreMetodo(restoThisFact.getLexema());
        } else {
            msg = "el metodo " + restoThisFact.getLexema() + "no es un metodo declarado en la clase"
                    + claseActual()+ ". Linea: " + getLineaActual();
            throw new Exception(msg);
        }
        a.setAsignable(false);
        return a;
    }
    //TODO buscarTipoVar

    public atributo restoThisFactPrimary(atributo restoThisFact) throws Exception {
        atributo a = new atributo();
        a.setAsignable(restoThisFact.isAsignable());
        a.setType(TS.buscarTipoDeVar(restoThisFact.getLexema()));
        return a;
    }
    //ok

    public atributo controlarAtributosPrivados(atributo primaryRec, String identificadorVariable) throws Exception {
        atributo a = new atributo();
        String msg;
        if (!primaryRec.isIsEmpty()) {
            msg = "los atributos de clase son privados  a la clase" + ". Linea: " + getLineaActual();
            throw new Exception(msg);
        } else {
            //ok var
            a.setType(TS.buscarTipoDeVar(identificadorVariable));
            a.setAsignable(false);
        }

        return a;

    }
    //ok

    public atributo actualArgsBeforeActualArgsResto(atributo actualArgs) throws Exception {
        atributo a = new atributo();
        String nombreClase;
        if (actualArgs.isIsSuper()) {
            nombreClase = TS.obtenerNombreClasePadre(claseActual());
        } else {
            if (actualArgs.type == null) {
                nombreClase = claseActual();
            } else {
                nombreClase = actualArgs.getType();
            }
        }
        if (actualArgs.isIsNew()) {
            ArrayList<parametro> parametros = new ArrayList<parametro>();
            a.setIsNew(actualArgs.isIsNew());
            a.setCantParametros(parametros.size());
            a.setPosParametros(0);
            a.setListaParametros(parametros);
        } else {
            ArrayList<parametro> parametros = TS.obtenerListaParametros(nombreClase, actualArgs.getNombreMetodo());
            a.setCantParametros(parametros.size());
            a.setPosParametros(0);
            a.setListaParametros(parametros);
        }
        return a;
    }

    public atributo actualArgsTipoRetornoMetodo(atributo actualArgs) throws Exception {
        atributo a = new atributo();
        String nombreClase;
        if (actualArgs.getType() == null) {
            nombreClase = claseActual();
        } else {
            nombreClase = actualArgs.getType();
        }
        if (actualArgs.isIsNew()) {
            a.setType(actualArgs.getNombreMetodo());
        } else {
            a.setType(TS.tipoRetornoMetodo(nombreClase, actualArgs.getNombreMetodo()));
        }
        return a;
    }
    //ok

    public atributo actualArgsRestoBeforeExprList(atributo actualArgsResto) {
        atributo a = new atributo();
        a.setPosParametros(actualArgsResto.getPosParametros());
        a.setCantParametros(actualArgsResto.getCantParametros());
        a.setListaParametros(actualArgsResto.getListaParametros());
        return a;
    }
    //ok

    public void controlarCantidadParametrosActuales(atributo actualArgsResto, atributo exprList) throws Exception {
        String msg;
        if (actualArgsResto.cantParametros != exprList.getPosParametros()) {
            msg = "\n<---------- ERROR en el analisis ---------->\nTipo de error: semantico\n"
                    + "Detalle:La cantidad de parametros actuales no corresponden con los paramtros Formales"
                    + "\nEncontrado en linea: " + getLineaActual() + "\n<------------------------------------------>";

            throw new Exception(msg);
        }
    }
    //ok

    public atributo exprListExpToExprListFact(atributo exprList, atributo exp) throws Exception {
        String msg;
        atributo a = new atributo();
        String tipoParametroFormal = TS.obtenerParametro(exprList.getListaParametros(), exprList.getPosParametros(), exprList.getCantParametros()).getTipo();
        if (!TS.sonTiposAdmisibles(tipoParametroFormal, exp.getType())) {
            msg = "\n<---------- ERROR en el analisis ---------->\nTipo de error: semantico\n"
                    + "Detalle: Tipo de los parametros incompatibles."
                    + "\nEncontrado en linea: " + lineaActual + "\n<------------------------------------------>";
            throw new Exception(msg);
        } else {
            a.setPosParametros(exprList.getPosParametros() + 1);
            a.setCantParametros(exprList.getCantParametros());
            a.setListaParametros(exprList.getListaParametros());
        }
        return a;
    }
    //ok

    public atributo exprListFactToExprList(atributo expListFact) {
        atributo a = new atributo();
        a.setPosParametros(expListFact.getPosParametros());
        a.setCantParametros(expListFact.getCantParametros());
        a.setListaParametros(expListFact.getListaParametros());
        return a;
    }
    //ok

    public atributo asignarPosParametro(atributo explist) {
        atributo a = new atributo();
        a.setPosParametros(explist.getPosParametros());
        return a;
    }
}
